#include "pvm/pvmapi.h"
#include "pvm/pvmoptions.h"

#include "lib/softwaremixer/pvmsoftmixerfastint.h"
#include "lib/pvmvoice.h"
#include "lib/pvmstrings.h"
#include "lib/softwaremixer/pvmresamplerint.h"
#include "lib/softwaremixer/pvmmixdatafastint.h"

#include "lib/memory/pvmmemory.h"


//#define PVM_MIXER_TMP_BUF_SIZE	1024

class PVMVoiceSlot : public PVMAllocableObject
{
protected:
	IPVMVoice*	voice;
	pvm_uint32	srcChanels;
	pvm_uint32	srcRate;
	pvm_uint32	volume;
	pvm_int32	panning;
	pvm_uint32	bitsPerSample;
	pvm_uint32	dstRate;
	IPVMVoiceResamplerInt* resampler;
	pvm_uint32	resamplerType;

	TVoiceCallbackProc	callbackProc;
	pvm_int64			callbackPeriod;
	pvm_int64			timeFromLastCallback;
	void*				calbackParam;

	pvm_bool scheduleToStop;
	pvm_bool usingResampler;
	pvm_bool renderSilenceVoice;
	pvm_bool isAliveCached;

	PVMSoftMixerFastInt* mixer;
	volatile pvm_bool markToFreeVoice;
	pvm_uint32 playingAt;
private:
	pvm_bool MakeEmpty();
public:
	PVMVoiceSlot();
	~PVMVoiceSlot();

	void SetMixer(PVMSoftMixerFastInt* mixer) {this->mixer = mixer;}

	void SetVoice(IPVMVoice* voice, pvm_uint32 dstRate, pvm_uint32 bitsPerSample, TVoiceCallbackProc callbackProc, pvm_uint32 callbackPeriod, void* calbackParam);
	void MarkMakeEmpty(pvm_uint32 playingAt);
	pvm_bool HasOutputData();
	pvm_bool IsAliveHasData();
	pvm_bool IsAlive();
	pvm_bool IsAliveCached() const {return isAliveCached;}
	pvm_bool HasVoice() const {return voice!=NULL || markToFreeVoice; }
	pvm_bool GetPause();
	void SetPause(pvm_uint32 chanelNum, pvm_bool pause);
	pvm_uint32 SrcChanelsNum() const {return srcChanels;}
	void SetRate(pvm_uint32 rate);

	pvm_bool SetPositionMS(pvm_int32 position);
	pvm_int32 GetPositionMS();

	pvm_bool SetVoiceOption(const pvm_char* optionName, void* param, pvm_uint32 paramSize);
	pvm_bool GetVoiceOption(const pvm_char* optionName, void* param, pvm_uint32* paramSize);

	pvm_uint32 FillBuffer(pvm_uint32 playingAt, void *buffer, pvm_uint32 numSamples);

	pvm_uint32 GetVolume() const;
	void SetVolume(pvm_uint32 volume);
	pvm_int32 GetPanning() const;
	void SetPanning(pvm_int32 panning);
	pvm_int32 GetLoopCount();
	void SetLoopCount(pvm_int32 loopCount);
	pvm_bool SetLoopInSamples(pvm_int64 loopFrom, pvm_int64 loopTo);
	pvm_bool GetLoopInSamples(pvm_int64 &loopFrom, pvm_int64 &loopTo);
	pvm_bool GetLoopInMS(pvm_int32 &loopFrom, pvm_int32 &loopTo);
	pvm_uint32 GetRate();
	void SetRenderSilentVoice(pvm_bool flag) {renderSilenceVoice = flag;};
	pvm_bool GetRenderSilentVoice() const {return renderSilenceVoice;};

	void ChangeResampler(pvm_uint32 type);
	pvm_uint32 GetResamplerType() const {return resamplerType;};

	pvm_bool IsMarkedToFree() {return markToFreeVoice;}
	void FreeDelayed();
	void OnIdle();
};

////////////////////////////////////////////////////////////////

PVMVoiceSlot::PVMVoiceSlot()
{
	mixer = NULL;

	markToFreeVoice = false;

	voice = NULL;
	srcChanels = 0;
	srcRate = 0;
	volume = 256;
	panning = 0;

	bitsPerSample = 0;
	dstRate = 0;

	resamplerType = EResamplerDefault;
	
	resampler = PVMCreateVoiceResamplerInt(resamplerType);

	callbackProc = 0;
	callbackPeriod = 0;
	timeFromLastCallback = 0;
	calbackParam = NULL;

	scheduleToStop = false;
	usingResampler = false;
	renderSilenceVoice = true;

	isAliveCached = false;
	playingAt = 0xffffffff;
}

void PVMVoiceSlot::ChangeResampler(pvm_uint32 type)
{
	IPVMVoiceResamplerInt* newResampler = PVMCreateVoiceResamplerInt(type);
	if(newResampler==NULL)
		return;

	pvm_uint32 oldRate = resampler->GetRate();
	resampler->Clear();
	delete( resampler);
	resampler = newResampler;
	resamplerType = type;
	if(voice!=NULL&&usingResampler!=false)
		resampler->Set(voice, dstRate, bitsPerSample);
	resampler->SetRate(oldRate);
}

pvm_uint32 PVMVoiceSlot::GetRate()
{
	if(usingResampler==false)
		return 100;
	if(resampler==NULL)
		return 100;

	return resampler->GetRate();
}

pvm_bool PVMVoiceSlot::SetPositionMS(pvm_int32 position)
{
	return voice->SetPositionMS(position);
}

pvm_int32 PVMVoiceSlot::GetPositionMS()
{
	return voice->GetPositionMS();
}

pvm_bool PVMVoiceSlot::SetVoiceOption(const pvm_char* optionName, void* param, pvm_uint32 paramSize)
{
	return voice->SetOption(optionName, param, paramSize);
}

pvm_bool PVMVoiceSlot::GetVoiceOption(const pvm_char* optionName, void* param, pvm_uint32* paramSize)
{
	return voice->GetOption(optionName, param, paramSize);
}

void PVMVoiceSlot::SetRate(pvm_uint32 rate)
{
	if(voice==NULL)
		return;

	if(usingResampler!=false&&resampler!=NULL)
	{
		resampler->SetRate(rate);
		return;
	}
	
	if(rate==100||resampler==NULL)
		return;

	resampler->Set(voice, dstRate, bitsPerSample);
	resampler->SetRate(rate);
	usingResampler = true;
}

pvm_bool PVMVoiceSlot::GetPause()
{
	if(!voice)
		return false;
	return voice->GetPause();
}

void PVMVoiceSlot::SetPause(pvm_uint32 chanelNum, pvm_bool pause)
{
	if(voice)
	{
		voice->SetPause(pause);
		if(callbackProc==NULL)
			return;
		if(pause)
		{
			callbackProc(chanelNum, EVOICE_PAUSED, -1, calbackParam);
		}
		else
		{
			callbackProc(chanelNum, EVOICE_PLAYING, -1, calbackParam);
			voice->OnIdle();
		}
	}
}

pvm_int32 PVMVoiceSlot::GetLoopCount()
{
	if(!voice)
		return 0;
	return voice->GetLoopCount();
}

void PVMVoiceSlot::SetLoopCount(pvm_int32 loopCount)
{
	if(voice)
		voice->SetLoopCount(loopCount);
}

pvm_bool PVMVoiceSlot::SetLoopInSamples(pvm_int64 loopFrom, pvm_int64 loopTo)
{
	if(voice)
		return voice->SetLoopInSamples(loopFrom, loopTo);

	return false;
}
pvm_bool PVMVoiceSlot::GetLoopInSamples(pvm_int64 &loopFrom, pvm_int64 &loopTo)
{
	if(voice)
		return voice->GetLoopInSamples(loopFrom, loopTo);

	return false;
}

pvm_bool PVMVoiceSlot::GetLoopInMS(pvm_int32 &loopFrom, pvm_int32 &loopTo)
{
	if(voice)
		return voice->GetLoopInMS(loopFrom, loopTo);

	return false;
}

void PVMVoiceSlot::SetVoice(IPVMVoice* voice, pvm_uint32 dstRate, pvm_uint32 bitsPerSample, TVoiceCallbackProc callbackProc, pvm_uint32 callbackPeriod, void* calbackParam)
{
	this->voice = voice;
	this->voice->AddRef();
	this->voice->SetIsOwned(true);
	pvm_uint32 srcBits;
	voice->GetFormat(srcRate, srcBits, srcChanels);
	this->dstRate = dstRate;
	this->bitsPerSample = bitsPerSample;
	if(dstRate!=srcRate)
	{
		resampler->Set(voice, dstRate, bitsPerSample);
		usingResampler = true;
	}
	else
	{
		usingResampler = false;
	}

	timeFromLastCallback = 0;
	this->callbackProc = callbackProc;
	this->callbackPeriod = callbackPeriod*1000;
	this->calbackParam = calbackParam;
	scheduleToStop = false;
	renderSilenceVoice = true;
	isAliveCached = true;

	voice->OnIdle();
}

void PVMVoiceSlot::MarkMakeEmpty(pvm_uint32 playingAt)
{
	this->playingAt = playingAt;
	if(mixer!=NULL && mixer->IsFreeSlotsDelayed())
	{
		if(markToFreeVoice)
			return;
		markToFreeVoice = true;
		return;
	}


	MakeEmpty();
}

pvm_bool PVMVoiceSlot::MakeEmpty()
{
	volatile pvm_bool wasDestroyed = false;
	if(voice!=NULL)
	{
		voice->SetIsOwned(false);
		voice->Release();
		wasDestroyed = true;
	}

	if(resampler)
	{
		resampler->Clear();
	}

	voice = 0;
	srcRate = 0;
	srcChanels = 0;
	panning = 0;
	volume = 256;

	if(callbackProc!=NULL)
	{
		callbackProc(playingAt, EVOICE_STOPPED, -1, calbackParam);
	}

	timeFromLastCallback = 0;
	this->callbackProc = 0;
	this->callbackPeriod = 0;
	this->calbackParam = 0;
	scheduleToStop = false;
	usingResampler = false;

	return wasDestroyed;
}

void PVMVoiceSlot::FreeDelayed()
{
	if(!markToFreeVoice)
		return;
	
	MakeEmpty();

	if(voice==NULL)
		markToFreeVoice = false;
}

void PVMVoiceSlot::OnIdle()
{
	if(IsAlive() && voice!=NULL)
		voice->OnIdle();
}

pvm_bool PVMVoiceSlot::IsAliveHasData()
{
	if(voice!=NULL)
	{
		if(voice->GetPause())
			return false;
		else
			return true;
	}

	if(usingResampler!=false && resampler!=NULL && resampler->IsEmpty()==false)
		return true;

	return false;
}

pvm_bool PVMVoiceSlot::HasOutputData()
{
	if(scheduleToStop)
		return false;

	if(voice!=NULL)
	{
		if(voice->IsAlive())
		{
			if(voice->GetPause())
				return false;
			else
				return true;
		}
	}

	if(usingResampler!=false && resampler!=NULL && resampler->IsEmpty()==false)
		return true;

	return false;
}

pvm_bool PVMVoiceSlot::IsAlive()
{
	if(markToFreeVoice)
	{
		isAliveCached = false;
		return false;
	}

	if(scheduleToStop)
	{
		isAliveCached = false;
		return false;
	}

	if(voice!=NULL)
	{
		if(voice->IsAlive())
		{
			isAliveCached = true;
			return true;
		}
	}

	if(usingResampler && resampler!=NULL && !resampler->IsEmpty())
	{
		isAliveCached = true;
		return true;
	}

	isAliveCached = false;
	return false;
}

PVMVoiceSlot::~PVMVoiceSlot()
{
	if(voice!=NULL)
	{
		voice->SetIsOwned(false);
		voice->Release();
	}
	voice = NULL;
	delete( resampler);
	resampler = NULL;

	mixer = NULL;
}

static float frequency = 220;
static float increment = (float)(2*3.14159265) * frequency / 22050; // angular increment for each sample
#include <math.h>


pvm_uint32 PVMVoiceSlot::FillBuffer(pvm_uint32 playingAt, void *buffer, pvm_uint32 numSamples)
{
	pvm_uint32 samplesRendered = 0;

	if(usingResampler==false)
	{
		samplesRendered = FillBufferFromVoice(voice, buffer, numSamples, bitsPerSample);
	}
	else
	{
		samplesRendered = resampler->FillBuffer(buffer, numSamples);//bits per sample are passed via "set" function
	}

	if(callbackProc!=NULL && callbackPeriod>0)
	{
		timeFromLastCallback += ((((pvm_int64)samplesRendered)/srcChanels)*1000000)/dstRate;
		if(timeFromLastCallback>=callbackPeriod)
		{
			int callbackRetVal = callbackProc(playingAt, EVOICE_PLAYING, voice->GetPositionMS(), calbackParam);
			if(callbackRetVal<0)
			{
				scheduleToStop = true;
			}
			else if(callbackRetVal>0)
			{
				SetPause(playingAt, true);
			}
			timeFromLastCallback = 0;
		}
	}

	return samplesRendered;
}

pvm_uint32 PVMVoiceSlot::GetVolume() const
{
	return volume;
}

void PVMVoiceSlot::SetVolume(pvm_uint32 volume)
{
	this->volume = volume;
}

pvm_int32 PVMVoiceSlot::GetPanning() const
{
	return panning;
}

void PVMVoiceSlot::SetPanning(pvm_int32 panning)
{
	this->panning = panning;
}

//*****************************************************************************
////////////////////////////////////////////////////////////////////////////////


PVMSoftMixerFastInt::PVMSoftMixerFastInt()
{
	voicesSlots = NULL;
	maxVoices = 0;

	voicesActive = 0;
	mixerInitialized = false;
	globalVolume = 0;
	sampleRate = 0;
	bitsPerSample = 0;
	bytesPerSample = 0;
	chanelsNum = 0;
	unsignedOutput = false;

	renderBuffer = NULL;
	renderBufferSize = 0;
	forceProcessOnIdle = 0;
}

PVMSoftMixerFastInt::~PVMSoftMixerFastInt()
{
	StopAll();

	if(voicesSlots)
		delete[](voicesSlots);

	voicesSlots = NULL;
	maxVoices = 0;
	sampleRate = 0;
	bitsPerSample = 0;
	chanelsNum = 0;

	PVMMemoryFree(renderBuffer);
	renderBuffer = NULL;
	renderBufferSize = 0;
}

////////////////////////////////////////////////////////////////////////////////
pvm_bool PVMSoftMixerFastInt::Init(pvm_uint32 maxVoices, pvm_uint32 sampleRate, pvm_uint32 bitsPerSample, pvm_uint32 chanelsNum)
{
	if(mixerInitialized)
		DeInit();

	if(chanelsNum>2||(bitsPerSample!=8&&bitsPerSample!=16))
		return false;//only mono/stereo mixing supported

	if(!PVMInitCritical(&renderCritical))
		return false;

	voicesActive = 0;
	this->maxVoices = maxVoices;
	voicesSlots = new PVMVoiceSlot[maxVoices];

	for(pvm_uint i=0; i<maxVoices; i++)
		voicesSlots[i].SetMixer(this);

	if(!voicesSlots)
	{
		PVMDeinitCritical(&renderCritical);
		return false;
	}

	globalVolume = 256;

	this->sampleRate = sampleRate;
	this->bitsPerSample = bitsPerSample;
	this->bytesPerSample = bitsPerSample>>3;
	this->chanelsNum = chanelsNum;
	
	mixerInitialized = true;

	if(bitsPerSample==8)
		unsignedOutput = true;
	else
		unsignedOutput = false;

	return true;
}

void PVMSoftMixerFastInt::DeInit()
{
	if(!mixerInitialized)
		return;

	StopAll();

	PVMEnterCritical(&renderCritical);

	delete[](voicesSlots);
	voicesSlots = NULL;
	maxVoices = 0;
	voicesActive = 0;
	globalVolume = 0;
	mixerInitialized = false;
	
	PVMLeaveCritical(&renderCritical);

	PVMDeinitCritical(&renderCritical);
}

pvm_bool PVMSoftMixerFastInt::IsInitialized()
{
	return mixerInitialized;
}

pvm_uint32 PVMSoftMixerFastInt::GetMaxVoices()
{
	return maxVoices;
}

void PVMSoftMixerFastInt::SetGlobalVolume(pvm_uint32 volume)
{
	if(volume>256)
		volume = 256;

	globalVolume = volume;
}

pvm_uint32 PVMSoftMixerFastInt::GetGlobalVolume()
{
	return globalVolume;
}

void PVMSoftMixerFastInt::StopAll()
{
	if(!mixerInitialized)
		return;

	PVMEnterCritical(&renderCritical);
	for(pvm_uint32 i=0; i<maxVoices; i++)
	{
		voicesSlots[i].MarkMakeEmpty(i);
	}
	voicesActive = 0;
	PVMLeaveCritical(&renderCritical);
}


pvm_bool PVMSoftMixerFastInt::HasMoreData()
{
	if(!mixerInitialized||voicesActive==0)
		return false;

	pvm_bool hasMoreData = false;
	PVMEnterCritical(&renderCritical);
	for(pvm_uint32 i=0; i<maxVoices; i++)
	{
		if(voicesSlots[i].IsAlive())
		{
			if(voicesSlots[i].GetPause()==false)
				hasMoreData = true;
		}
		else
		{
			if(voicesSlots[i].HasVoice() && !voicesSlots[i].IsMarkedToFree())
			{
				voicesSlots[i].MarkMakeEmpty(i);
				voicesActive--;
			}
		}
	}
	PVMLeaveCritical(&renderCritical);
	return hasMoreData;
}

pvm_uint32 PVMSoftMixerFastInt::FillBuffer(void* buffer, pvm_uint32 bufferSizeInSamples)
{
	pvm_uint32 samplesFilledMax = 0;
	pvm_uint32 bufferSizeInbytes = bufferSizeInSamples*(bitsPerSample>>3);

	if(!mixerInitialized||voicesActive==0)
	{
		if(unsignedOutput)
			memset(buffer, 127, bufferSizeInbytes);
		else
			memset(buffer, 0, bufferSizeInbytes);

		return 0;
	}

	if(bufferSizeInbytes>renderBufferSize)
	{
		ResizeRenderBuffer(bufferSizeInbytes);
	}

	PVMEnterCritical(&renderCritical);
	if(bitsPerSample==8)
		memset(buffer, 127, bufferSizeInbytes);//TODO: should I replace 0 with 127?
	else
		memset(buffer, 0, bufferSizeInbytes);

	pvm_uint32 sampleNum;

	pvm_uint32 voicesRendered = 0;
	pvm_uint32 oldChanelsActive = voicesActive;
	pvm_uint32 samplesFilled;

	for(pvm_uint32 i=0; i<maxVoices; i++)
	{
		if(voicesSlots[i].IsAlive())
		{
			voicesRendered++;
			if(voicesSlots[i].IsAliveHasData())
			{
				if(voicesSlots[i].GetVolume()==0 && voicesSlots[i].GetRenderSilentVoice()==false)
					continue;
				pvm_int32 mixingVolume = (pvm_int32)((((pvm_uint64)globalVolume)*voicesSlots[i].GetVolume())>>8);
				if(voicesSlots[i].SrcChanelsNum()==chanelsNum)
				{
					//input/output channels number is equal
					samplesFilled = voicesSlots[i].FillBuffer(i, renderBuffer, bufferSizeInSamples);
					if(samplesFilled>samplesFilledMax)
						samplesFilledMax = samplesFilled;
					if(mixingVolume==0)
						continue;
					switch(bitsPerSample)
					{
					case 8:
						{
							signed char *srcData, *dstData;
							srcData = (signed char*)renderBuffer;
							dstData = (signed char*)buffer;
							if(chanelsNum==1||voicesSlots[i].GetPanning()==0)
							{
								int newSample;
								if(mixingVolume==256)
								{
									for(sampleNum=0; sampleNum<samplesFilled; sampleNum++, dstData++, srcData++)
									{
										newSample = *dstData + *srcData;
										if(newSample>127)
											newSample = 127;
										else if(newSample<-128)
											newSample = -128;

										*dstData = newSample;
									}
								}
								else
								{
									for(sampleNum=0; sampleNum<samplesFilled; sampleNum++, dstData++, srcData++)
									{
										newSample = *dstData + ((((int)(*srcData))*mixingVolume)>>8);
										if(newSample>127)
											newSample = 127;
										else if(newSample<-128)
											newSample = -128;

										*dstData = newSample;
									}
								}
							}
							else
							{
								int panning = voicesSlots[i].GetPanning();
								int newSampleL;
								int newSampleR;
								//stereo with panning
								if(mixingVolume==256)
								{
									//without volume
									for(sampleNum=0; sampleNum<samplesFilled; sampleNum+=2, dstData+=2, srcData+=2)
									{
										int sampleL = *srcData;
										int sampleR = *(srcData + 1);
										if(panning<0)
										{
											newSampleL = sampleL + ((sampleR*(-panning))>>8) + *dstData;
											newSampleR = ((sampleR*(256 + panning))>>8) + *(dstData + 1);
										}
										else
										{
											newSampleL = ((sampleL*(256 - panning))>>8) + *dstData;
											newSampleR = sampleR + ((sampleL*(panning))>>8) + *(dstData + 1);
										}

										
										if(newSampleL>127)
											newSampleL = 127;
										else if(newSampleL<-128)
											newSampleL = -128;

										if(newSampleR>127)
											newSampleR = 127;
										else if(newSampleR<-128)
											newSampleR = -128;

										*dstData = newSampleL;
										*(dstData + 1) = newSampleR;
									}
								}
								else
								{
									//with volume
									for(sampleNum=0; sampleNum<samplesFilled; sampleNum+=2, dstData+=2, srcData+=2)
									{
										int sampleL = *srcData;
										int sampleR = *(srcData + 1);
										if(panning<0)
										{
											newSampleL = sampleL + ((sampleR*(-panning))>>8);
											newSampleR = (sampleR*(256 + panning))>>8;
										}
										else
										{
											newSampleR = sampleR + ((sampleL*(panning))>>8);
											newSampleL = (sampleL*(256 - panning))>>8;
										}

										newSampleL = *dstData + ((((int)(newSampleL))*mixingVolume)>>8);
										newSampleR = *(dstData + 1) + ((((int)(newSampleR))*mixingVolume)>>8);
										
										if(newSampleL>127)
											newSampleL = 127;
										else if(newSampleL<-128)
											newSampleL = -128;

										if(newSampleR>127)
											newSampleR = 127;
										else if(newSampleR<-128)
											newSampleR = -128;

										*dstData = newSampleL;
										*(dstData + 1) = newSampleR;
									}
								}
							}
						}
						break;
					case 16:
						{
							short *srcData, *dstData;
							srcData = (short*)renderBuffer;
							dstData = (short*)buffer;
							if(chanelsNum==1||voicesSlots[i].GetPanning()==0)
							{
								int newSample;
								if(mixingVolume==256)
								{
									for(sampleNum=0; sampleNum<samplesFilled; sampleNum++, dstData++, srcData++)
									{
										newSample = *dstData + *srcData;
										if(newSample>32767)
											newSample = 32767;
										else if(newSample<-32768)
											newSample = -32768;

										*dstData = newSample;
									}
								}
								else
								{
									for(sampleNum=0; sampleNum<samplesFilled; sampleNum++, dstData++, srcData++)
									{
										newSample = *dstData + ((((int)(*srcData))*mixingVolume)>>8);
										if(newSample>32767)
											newSample = 32767;
										else if(newSample<-32768)
											newSample = -32768;

										*dstData = newSample;
									}
								}
							}
							else
							{
								//stereo with panning
								int panning = voicesSlots[i].GetPanning();
								int newSampleL;
								int newSampleR;
								if(mixingVolume==256)
								{
									for(sampleNum=0; sampleNum<samplesFilled; sampleNum+=2, dstData+=2, srcData+=2)
									{
																				int sampleL = *srcData;
										int sampleR = *(srcData + 1);
										if(panning<0)
										{
											newSampleL = sampleL + ((sampleR*(-panning))>>8) + *dstData;
											newSampleR = ((sampleR*(256 + panning))>>8) + *(dstData + 1);
										}
										else
										{
											newSampleL = ((sampleL*(256 - panning))>>8) + *dstData;
											newSampleR = sampleR + ((sampleL*(panning))>>8) + *(dstData + 1);
										}

										if(newSampleL>32767)
											newSampleL = 32767;
										else if(newSampleL<-32768)
											newSampleL = -32768;

										if(newSampleR>32767)
											newSampleR = 32767;
										else if(newSampleR<-32768)
											newSampleR = -32768;

										*dstData = newSampleL;
										*(dstData+1) = newSampleR;
									}
								}
								else
								{
									for(sampleNum=0; sampleNum<samplesFilled; sampleNum+=2, dstData+=2, srcData+=2)
									{
										int sampleL = *srcData;
										int sampleR = *(srcData + 1);
										if(panning<0)
										{
											newSampleL = sampleL + ((sampleR*(-panning))>>8);
											newSampleR = (sampleR*(256 + panning))>>8;
										}
										else
										{
											newSampleR = sampleR + ((sampleL*(panning))>>8);
											newSampleL = (sampleL*(256 - panning))>>8;
										}

										newSampleL = *dstData + ((((int)(newSampleL))*mixingVolume)>>8);
										newSampleR = *(dstData + 1) + ((((int)(newSampleR))*mixingVolume)>>8);

										if(newSampleL>32767)
											newSampleL = 32767;
										else if(newSampleL<-32768)
											newSampleL = -32768;

										if(newSampleR>32767)
											newSampleR = 32767;
										else if(newSampleR<-32768)
											newSampleR = -32768;

										*dstData = newSampleL;
										*(dstData + 1) = newSampleR;
									}
								}
							}
						}
						break;
					}
				}
				else
				{
					//different channels number
					//!!!!!!!!!!!!!!!!!!!!!!!
					pvm_uint32 offsetInDestination = 0;
					pvm_uint32 dstSteps = bufferSizeInSamples/chanelsNum;
					pvm_uint32 srcSamplesToFill;
					pvm_uint32 samplesFilledTotal = 0;
					pvm_uint32 mixedSizeInSamples = 0;
					pvm_uint32 mixedSizeInSteps = 0;
					
					while(samplesFilledTotal<bufferSizeInSamples)
					{
						srcSamplesToFill = dstSteps*voicesSlots[i].SrcChanelsNum();
						if(srcSamplesToFill>bufferSizeInSamples)
						{
							srcSamplesToFill = (bufferSizeInSamples/voicesSlots[i].SrcChanelsNum())*voicesSlots[i].SrcChanelsNum();
						}

						samplesFilled = voicesSlots[i].FillBuffer(i, renderBuffer, srcSamplesToFill);
						if(samplesFilled<=0)
							break;

						int newOffset=0;

						switch(bitsPerSample)
						{
						case 8:
							{
								if(chanelsNum==1)
								{
									newOffset = MixDataToMono8((signed char*)renderBuffer, voicesSlots[i].SrcChanelsNum(), samplesFilled, ((signed char*)buffer) + offsetInDestination, mixingVolume);
									mixedSizeInSteps = mixedSizeInSamples = newOffset;
								}
								else
								{
									newOffset = MixDataToStereo8((signed char*)renderBuffer, voicesSlots[i].SrcChanelsNum(), samplesFilled, ((signed char*)buffer) + offsetInDestination, mixingVolume, voicesSlots[i].GetPanning());
									mixedSizeInSamples = newOffset;
									mixedSizeInSteps = mixedSizeInSamples>>1;
								}
							}
							break;
						case 16:
							{
								if(chanelsNum==1)
								{
									newOffset = MixDataToMono16((short*)renderBuffer, voicesSlots[i].SrcChanelsNum(), samplesFilled, (short*)(((char*)buffer) + offsetInDestination), mixingVolume);
									mixedSizeInSamples = newOffset>>1;
									mixedSizeInSteps = mixedSizeInSamples;
								}
								else
								{
									switch (voicesSlots[i].SrcChanelsNum())
									{
									case 1:
										newOffset = MixDataToStereo16FromMono((short*)renderBuffer, samplesFilled, (short*)(((char*)buffer) + offsetInDestination), mixingVolume, voicesSlots[i].GetPanning());
										break;
									case 2:
										newOffset = MixDataToStereo16FromStereo((short*)renderBuffer, samplesFilled, (short*)(((char*)buffer) + offsetInDestination), mixingVolume, voicesSlots[i].GetPanning());
										break;
									default:
										newOffset = MixDataToStereo16((short*)renderBuffer, voicesSlots[i].SrcChanelsNum(), samplesFilled, (short*)(((char*)buffer) + offsetInDestination), mixingVolume, voicesSlots[i].GetPanning());
									}
									mixedSizeInSamples = newOffset>>1;
									mixedSizeInSteps = mixedSizeInSamples>>1;
								}
							}
							break;
							default:
							{
									PVMLeaveCritical(&renderCritical);
									return samplesFilledMax;
							}
						}

						offsetInDestination += newOffset;
						samplesFilledTotal += mixedSizeInSamples;
						dstSteps -= mixedSizeInSteps;
					}

					if(samplesFilledTotal>samplesFilledMax)
						samplesFilledMax = samplesFilledTotal;
				}
			}
		}
		else
		{
			if(voicesSlots[i].HasVoice() && !voicesSlots[i].IsMarkedToFree())
			{
				voicesSlots[i].MarkMakeEmpty(i);
				voicesActive--;
			}
		}
		if(voicesRendered>=oldChanelsActive)
			break;
	}

	if(unsignedOutput)
	{
		if(bitsPerSample==8)
		{
			for(pvm_uint32 i=0; i<bufferSizeInSamples; i++)
			{
				((unsigned char*)buffer)[i] = ((int)(((char*)buffer)[i])) + 128;
			}
		}
	}

	PVMLeaveCritical(&renderCritical);

	return samplesFilledMax;
}

void PVMSoftMixerFastInt::ResizeRenderBuffer(pvm_uint32 bufferSizeInBytes)
{
	PVMMemoryFree(renderBuffer);
	renderBuffer = NULL;
	renderBufferSize = 0;

	renderBuffer = (pvm_int8*)PVMMemoryAlloc(bufferSizeInBytes);
	renderBufferSize = bufferSizeInBytes;
}

pvm_uint32 PVMSoftMixerFastInt::GetRenderBufferSizeInBytes()
{
	return renderBufferSize;
}

pvm_int32 PVMSoftMixerFastInt::Play(IPVMVoice *voice, pvm_uint32 voiceNumAndFlags, TVoiceCallbackProc callbackProc, pvm_uint32 callbackPeriod, void* calbackParam)
{
	if(!mixerInitialized)
		return -1;

	if(voice==NULL||voice->GetChanelsNum()>2)
		return -1;

	pvm_uint32 playAt = voiceNumAndFlags;

	PVMEnterCritical(&renderCritical);

	if(playAt==PVM_VOICE_FREE)
	{
		pvm_uint32 i;
		for(i=0; i<maxVoices; i++)
		{
			if(voicesSlots[i].IsAliveCached()==false && !voicesSlots[i].IsMarkedToFree())
			{
				playAt = i;
				break;
			}
		}

		if(playAt==PVM_VOICE_FREE)
		{
			PVMLeaveCritical(&renderCritical);
			return -1;
		}
	}
	else if((playAt&0x80000000u)!=0 || playAt>=maxVoices)
	{
		PVMLeaveCritical(&renderCritical);
		return -1;
	}

	if(voicesSlots[playAt].HasVoice() && !voicesSlots[playAt].IsMarkedToFree())
	{
		if(voicesSlots[playAt].IsMarkedToFree())
		{
			voicesSlots[playAt].FreeDelayed();
		}
		else
		{
			voicesSlots[playAt].MarkMakeEmpty(playAt);
		}
		voicesActive--;
		PVMLeaveCritical(&renderCritical);
	}

	voicesSlots[playAt].SetVoice(voice, sampleRate, bitsPerSample, callbackProc, callbackPeriod, calbackParam);
	voicesActive++;

	PVMLeaveCritical(&renderCritical);

	return playAt;
}

pvm_bool PVMSoftMixerFastInt::Stop(pvm_uint32 chanelNum)
{
	if(!mixerInitialized)
		return false;

	if(chanelNum>maxVoices)
		return false;

	pvm_bool retVal = false;
	PVMEnterCritical(&renderCritical);

	if(voicesSlots[chanelNum].HasVoice() && !voicesSlots[chanelNum].IsMarkedToFree())
	{
		voicesSlots[chanelNum].MarkMakeEmpty(chanelNum);
		voicesActive--;
		retVal = true;
	}

	PVMLeaveCritical(&renderCritical);

	return retVal;
}

pvm_bool PVMSoftMixerFastInt::IsVoiceFree(pvm_uint32 chanelNum)
{
	if(!mixerInitialized)
		return false;

	if(chanelNum>maxVoices)
		return false;

	return voicesSlots[chanelNum].IsAliveCached()==false;
}

pvm_bool PVMSoftMixerFastInt::SetRate(pvm_uint32 chanelNum, pvm_int32 value)
{
	if(!mixerInitialized)
		return false;

	if(chanelNum>maxVoices)
		return false;

	if(value<0)
		return false;

	pvm_bool retVal = false;
	PVMEnterCritical(&renderCritical);

	if(voicesSlots[chanelNum].IsAliveCached())
	{
		voicesSlots[chanelNum].SetRate(value);
		retVal = true;
	}

	PVMLeaveCritical(&renderCritical);

	return retVal;
}

pvm_bool PVMSoftMixerFastInt::SetPanning(pvm_uint32 chanelNum, pvm_int32 value)
{
	if(!mixerInitialized)
		return false;

	if(chanelNum>maxVoices)
		return false;

	pvm_bool retVal = false;
	PVMEnterCritical(&renderCritical);

	if(voicesSlots[chanelNum].IsAliveCached())
	{
		voicesSlots[chanelNum].SetPanning(value);
		retVal = true;
	}

	PVMLeaveCritical(&renderCritical);

	return retVal;
}

pvm_bool PVMSoftMixerFastInt::SetVolume(pvm_uint32 chanelNum, pvm_int32 value)
{
	if(!mixerInitialized)
		return false;

	if(chanelNum>maxVoices)
		return false;

	if(value<0)
		value = 0;

	if(value>256)
		value = 256;

	pvm_bool retVal = false;
	PVMEnterCritical(&renderCritical);

	if(voicesSlots[chanelNum].IsAliveCached())
	{
		voicesSlots[chanelNum].SetVolume(value);
		retVal = true;
	}

	PVMLeaveCritical(&renderCritical);

	return retVal;
}

pvm_bool PVMSoftMixerFastInt::SetLoopCount(pvm_uint32 chanelNum, pvm_int32 value)
{
	if(!mixerInitialized)
		return false;

	if(chanelNum>maxVoices)
		return false;

	pvm_bool retVal = false;
	PVMEnterCritical(&renderCritical);

	if(voicesSlots[chanelNum].IsAliveCached()&&voicesSlots[chanelNum].HasVoice())
	{
		voicesSlots[chanelNum].SetLoopCount(value);
		retVal = true;
	}

	PVMLeaveCritical(&renderCritical);

	return retVal;
}

pvm_bool PVMSoftMixerFastInt::SetLoopInSamples(pvm_uint32 chanelNum, pvm_int64 loopFrom, pvm_int64 loopTo)
{
	if(!mixerInitialized)
		return false;

	if(chanelNum>maxVoices)
		return false;

	pvm_bool retVal = false;
	PVMEnterCritical(&renderCritical);

	if(voicesSlots[chanelNum].IsAliveCached()&&voicesSlots[chanelNum].HasVoice())
	{
		retVal = voicesSlots[chanelNum].SetLoopInSamples(loopFrom, loopTo);
	}

	PVMLeaveCritical(&renderCritical);

	return retVal;
}

pvm_bool PVMSoftMixerFastInt::SetPause(pvm_uint32 chanelNum, pvm_bool value)
{
	if(!mixerInitialized)
		return false;

	if(chanelNum>maxVoices)
		return false;

	pvm_bool retVal = false;
	PVMEnterCritical(&renderCritical);

	if(voicesSlots[chanelNum].IsAliveCached()&&voicesSlots[chanelNum].HasVoice())
	{
		voicesSlots[chanelNum].SetPause(chanelNum, value);
		retVal = true;
	}

	PVMLeaveCritical(&renderCritical);

	return retVal;
}

pvm_bool PVMSoftMixerFastInt::SetRenderSilentVoice(pvm_uint32 chanelNum, pvm_bool value)
{
	if(!mixerInitialized)
		return false;

	if(chanelNum>maxVoices)
		return false;

	pvm_bool retVal = false;
	PVMEnterCritical(&renderCritical);

	if(voicesSlots[chanelNum].IsAliveCached()&&voicesSlots[chanelNum].HasVoice())
	{
		voicesSlots[chanelNum].SetRenderSilentVoice(value);
		retVal = true;
	}

	PVMLeaveCritical(&renderCritical);

	return retVal;
}

pvm_bool PVMSoftMixerFastInt::GetRate(pvm_uint32 chanelNum, pvm_int32& value)
{
	if(!mixerInitialized)
		return false;

	if(chanelNum>maxVoices)
		return false;

	if(value<0)
		return false;

	pvm_bool retVal = false;
	PVMEnterCritical(&renderCritical);

	if(voicesSlots[chanelNum].IsAliveCached())
	{
		value = voicesSlots[chanelNum].GetRate();
		retVal = true;
	}

	PVMLeaveCritical(&renderCritical);

	return retVal;
}

pvm_bool PVMSoftMixerFastInt::GetPanning(pvm_uint32 chanelNum, pvm_int32& value)
{
	if(!mixerInitialized)
		return false;

	if(chanelNum>maxVoices)
		return false;

	pvm_bool retVal = false;
	PVMEnterCritical(&renderCritical);

	if(voicesSlots[chanelNum].IsAliveCached())
	{
		value = voicesSlots[chanelNum].GetPanning();
		retVal = true;
	}

	PVMLeaveCritical(&renderCritical);

	return retVal;
}

pvm_bool PVMSoftMixerFastInt::GetVolume(pvm_uint32 chanelNum, pvm_int32& value)
{
	if(!mixerInitialized)
		return false;

	if(chanelNum>maxVoices)
		return false;

	if(value<0)
		return false;

	pvm_bool retVal = false;
	PVMEnterCritical(&renderCritical);

	if(voicesSlots[chanelNum].IsAliveCached())
	{
		value = voicesSlots[chanelNum].GetVolume();
		retVal = true;
	}

	PVMLeaveCritical(&renderCritical);

	return retVal;
}

pvm_bool PVMSoftMixerFastInt::GetLoopCount(pvm_uint32 chanelNum, pvm_int32& value)
{
	if(!mixerInitialized)
		return false;

	if(chanelNum>maxVoices)
		return false;

	pvm_bool retVal = false;
	PVMEnterCritical(&renderCritical);

	if(voicesSlots[chanelNum].IsAliveCached()&&voicesSlots[chanelNum].HasVoice())
	{
		value = voicesSlots[chanelNum].GetLoopCount();
		retVal = true;
	}

	PVMLeaveCritical(&renderCritical);

	return retVal;
}

pvm_bool PVMSoftMixerFastInt::GetLoopInSamples(pvm_uint32 chanelNum, pvm_int64 &loopFrom, pvm_int64 &loopTo)
{
	if(!mixerInitialized)
		return false;

	if(chanelNum>maxVoices)
		return false;

	pvm_bool retVal = false;
	PVMEnterCritical(&renderCritical);

	if(voicesSlots[chanelNum].IsAliveCached()&&voicesSlots[chanelNum].HasVoice())
	{
		retVal = voicesSlots[chanelNum].GetLoopInSamples(loopFrom, loopTo);
	}

	PVMLeaveCritical(&renderCritical);

	return retVal;
}

pvm_bool PVMSoftMixerFastInt::GetLoopInMS(pvm_uint32 chanelNum, pvm_int32 &loopFrom, pvm_int32 &loopTo)
{
	if(!mixerInitialized)
		return false;

	if(chanelNum>maxVoices)
		return false;

	pvm_bool retVal = false;
	PVMEnterCritical(&renderCritical);

	if(voicesSlots[chanelNum].IsAliveCached()&&voicesSlots[chanelNum].HasVoice())
	{
		retVal = voicesSlots[chanelNum].GetLoopInMS(loopFrom, loopTo);
	}

	PVMLeaveCritical(&renderCritical);

	return retVal;
}

pvm_bool PVMSoftMixerFastInt::GetPause(pvm_uint32 chanelNum, pvm_bool& value)
{
	if(!mixerInitialized)
		return false;

	if(chanelNum>maxVoices)
		return false;

	pvm_bool retVal = false;
	PVMEnterCritical(&renderCritical);

	if(voicesSlots[chanelNum].IsAliveCached()&&voicesSlots[chanelNum].HasVoice())
	{
		value = voicesSlots[chanelNum].GetPause();
		retVal = true;
	}

	PVMLeaveCritical(&renderCritical);

	return retVal;
}

pvm_bool PVMSoftMixerFastInt::GetRenderSilentVoice(pvm_uint32 chanelNum, pvm_bool& value)
{
	if(!mixerInitialized)
		return false;

	if(chanelNum>maxVoices)
		return false;

	pvm_bool retVal = false;
	PVMEnterCritical(&renderCritical);

	if(voicesSlots[chanelNum].IsAliveCached()&&voicesSlots[chanelNum].HasVoice())
	{
		value = voicesSlots[chanelNum].GetRenderSilentVoice();
		retVal = true;
	}

	PVMLeaveCritical(&renderCritical);

	return retVal;
}

pvm_bool PVMSoftMixerFastInt::SetPositionMS(pvm_uint32 chanelNum, pvm_int32 value)
{
	if(!mixerInitialized)
		return false;

	if(chanelNum>maxVoices)
		return false;

	pvm_bool retVal = false;
	PVMEnterCritical(&renderCritical);

	if(voicesSlots[chanelNum].IsAliveCached()&&voicesSlots[chanelNum].HasVoice())
	{
		retVal = voicesSlots[chanelNum].SetPositionMS(value);
	}

	PVMLeaveCritical(&renderCritical);

	return retVal;
}

pvm_bool PVMSoftMixerFastInt::GetPositionMS(pvm_uint32 chanelNum, pvm_int32& value)
{
	if(!mixerInitialized)
		return false;

	if(chanelNum>maxVoices)
		return false;

	pvm_bool retVal = false;
	PVMEnterCritical(&renderCritical);

	if(voicesSlots[chanelNum].IsAliveCached()&&voicesSlots[chanelNum].HasVoice())
	{
		value = voicesSlots[chanelNum].GetPositionMS();
		retVal = true;
	}

	PVMLeaveCritical(&renderCritical);

	return retVal;
}

pvm_bool PVMSoftMixerFastInt::SetVoiceOption(pvm_uint32 chanelNum, const pvm_char* optionName, void* param, pvm_uint32 paramSize)
{
	if(!mixerInitialized)
		return false;

	if(chanelNum>maxVoices)
		return false;

	pvm_bool retVal = false;
	PVMEnterCritical(&renderCritical);

	if(voicesSlots[chanelNum].IsAliveCached()&&voicesSlots[chanelNum].HasVoice())
	{
		retVal = voicesSlots[chanelNum].SetVoiceOption(optionName, param, paramSize);
	}

	PVMLeaveCritical(&renderCritical);

	return retVal;
}

pvm_bool PVMSoftMixerFastInt::GetVoiceOption(pvm_uint32 chanelNum, const pvm_char* optionName, void* param, pvm_uint32* paramSize)
{
	if(!mixerInitialized)
		return false;

	if(chanelNum>maxVoices)
		return false;

	pvm_bool retVal = false;
	PVMEnterCritical(&renderCritical);

	if(voicesSlots[chanelNum].IsAliveCached()&&voicesSlots[chanelNum].HasVoice())
	{
		retVal = voicesSlots[chanelNum].GetVoiceOption(optionName, param, paramSize);
	}

	PVMLeaveCritical(&renderCritical);

	return retVal;
}

pvm_bool PVMSoftMixerFastInt::SetOption(const pvm_char* optionName, void* param, pvm_uint32 paramSize)
{
	if(pvm_strcmp(optionName, _PVM_STR("mixer.resamplertype"))==0)
	{
		if(param==NULL||paramSize!=sizeof(int))
			return false;

		PVMEnterCritical(&renderCritical);
		for(pvm_uint32 i=0; i<maxVoices; i++)
		{
			voicesSlots[i].ChangeResampler(*((int*)param));
		}
		PVMLeaveCritical(&renderCritical);

		return true;
	};
	return false;
}

pvm_bool PVMSoftMixerFastInt::GetOption(const pvm_char* optionName, void* param, pvm_uint32* paramSize)
{
	if(pvm_strcmp(optionName, _PVM_STR("mixer.resamplertype"))==0)
	{
		if(param==NULL||paramSize==NULL||*paramSize!=sizeof(int))
			return false;

		if(maxVoices==0)
			return false;

		PVMEnterCritical(&renderCritical);
		*paramSize = sizeof(int);
		*((int*)param) = voicesSlots[0].GetResamplerType();
		PVMLeaveCritical(&renderCritical);

		return true;
	};
	return false;
}

pvm_bool PVMSoftMixerFastInt::BeginBatchParams()
{
	if(!mixerInitialized)
		return false;
	PVMEnterCritical(&renderCritical);
	return true;
}

void PVMSoftMixerFastInt::EndBatchParams()
{
	PVMLeaveCritical(&renderCritical);
}

pvm_bool PVMSoftMixerFastInt::SetPanningVolumeRateFast(pvm_uint32 chanelNum, pvm_int32 panning, pvm_int32 volume, pvm_int32 rate)
{
	voicesSlots[chanelNum].SetVolume(volume);
	voicesSlots[chanelNum].SetRate(rate);
	voicesSlots[chanelNum].SetPanning(panning);

	return true;
}

void PVMSoftMixerFastInt::OnIdle()
{
	if(!forceProcessOnIdle)
		return;

	for(pvm_uint i=0; i<maxVoices; i++)
	{
		voicesSlots[i].FreeDelayed();
		voicesSlots[i].OnIdle();
	}
}

void PVMSoftMixerFastInt::SetForceProcessingOnIdle(pvm_bool flag)
{
	forceProcessOnIdle = flag;
}

pvm_bool PVMSoftMixerFastInt::IsFreeSlotsDelayed()
{
	return forceProcessOnIdle;
}

pvm_uint32 FillBufferFromVoice(IPVMVoice* voice, void *buffer, pvm_uint32 numSamples, pvm_uint32 bitsPerSample)
{
	pvm_uint32 srcBitsPerSample = voice->GetBitsPerSample();
	if(bitsPerSample==srcBitsPerSample)
	{
		return voice->FillBuffer(buffer, numSamples);
	}
	//16->8
	else if(srcBitsPerSample==16 && bitsPerSample==8)
	{
		char tempBuffer[2048];
		pvm_uint32 srcSampleSize = 2;
		pvm_uint32 dstSampleSize = 1;
		pvm_uint32 srcStepSize = srcSampleSize*voice->GetChanelsNum();
		pvm_uint32 bufferSizeInSamples = (sizeof(tempBuffer)/srcStepSize)*srcSampleSize*voice->GetChanelsNum();
		pvm_uint32 samplesToFill = 0;

		pvm_uint32 tmpSamplesFilled;
		pvm_uint32 i;

		short *srcPtr;
		char *dstPtr;
		pvm_uint32 samplesFilled = 0;

		while(samplesFilled<numSamples)
		{
			samplesToFill = numSamples - samplesFilled;
			if(samplesToFill>bufferSizeInSamples)
			{
				samplesToFill = bufferSizeInSamples;
			}

			tmpSamplesFilled = voice->FillBuffer(tempBuffer, samplesToFill);

			if(tmpSamplesFilled<=0)
				return samplesFilled;

			srcPtr = (short*)&(tempBuffer[0]);
			dstPtr = ((char*)buffer) + samplesFilled*dstSampleSize;

			for(i=0; i<tmpSamplesFilled; i++)
			{
				*dstPtr = *srcPtr >> 8;

				srcPtr ++;
				dstPtr ++;
			}			

			samplesFilled += tmpSamplesFilled;
		}

		return samplesFilled;
	}//8->16
	else if(srcBitsPerSample==8&&bitsPerSample==16)
	{
		char tempBuffer[2048];
		pvm_uint32 srcSampleSize = 1;
		pvm_uint32 dstSampleSize = 2;
		pvm_uint32 srcStepSize = srcSampleSize*voice->GetChanelsNum();
		pvm_uint32 bufferSizeInSamples = (sizeof(tempBuffer)/srcStepSize)*srcSampleSize*voice->GetChanelsNum();
		pvm_uint32 samplesToFill = 0;
		pvm_uint32 tmpSamplesFilled;
		pvm_uint32 i;

		char *srcPtr;
		short *dstPtr;
		pvm_uint32 samplesFilled = 0;

		while(samplesFilled<numSamples)
		{
			samplesToFill = numSamples - samplesFilled;
			if(samplesToFill>bufferSizeInSamples)
			{
				samplesToFill = bufferSizeInSamples;
			}

			tmpSamplesFilled = voice->FillBuffer(tempBuffer, samplesToFill);

			if(tmpSamplesFilled<=0)
				return samplesFilled;

			srcPtr = &(tempBuffer[0]);
			dstPtr = (short*)(((char*)buffer) + samplesFilled*dstSampleSize);

			for(i=0; i<tmpSamplesFilled; i++)
			{
				*dstPtr = *((char*)srcPtr);
				*dstPtr = (*dstPtr - 127) << 8;

				srcPtr ++;
				dstPtr ++;
			}			

			samplesFilled += tmpSamplesFilled;
		}

		return samplesFilled;
	}

	return 0;//not supported conversation
}

